<?php

require_once 'jujucock.php';
require_once 'optparse.php';
require_once 'logger.php';

define('HOST', '127.0.0.1');
define('PORT', 54344);
define('SERVICE', 'ECHO');

///////////////////////////////////////////////////////////////////////

class   ClientJob   extends BaseJob
{
    private $peer_address;
    private $times;
    private $pad_bytes;
    private $action;
    
    private $count_times;
    private $count_bytes;
    private $time_start;
    private $time_stop;
    
    private $logger;
    
    public function __construct($peer_address, $times=10, $bytes=0)
    {
        $this->peer_address = $peer_address;
        $this->times = $times;
        $this->pad_bytes = str_repeat('A', $bytes);
        $this->action = NULL;
        
        $this->count_times = 0;
        $this->count_bytes = 0;
        $this->time_start = 0;
        $this->time_stop  = 0;
        
        $this->logger = getLogger();
    }
    
    public function currentAction()
    {
        return $this->action;
    }
    
    public function nextAction()
    {
        if (NULL === $this->action) {
            // the first time
            $this->time_start = microtime(true);
        }
        if ($this->count_times >= $this->times) {
            // the last time
            $this->time_stop = microtime(true);
            $time_last = $this->time_stop - $this->time_start;
            $tps = $this->times / $time_last;
            $bw  = $this->count_bytes / $time_last;
            if ($bw > 1048576) {
                $bw = sprintf('%.2f MB/s', $bw / 1048576.0);
            }
            elseif ($bw > 1024) {
                $bw = sprintf('%.2f KB/s', $bw / 1024.0);
            }
            else {
                $bw = sprintf('%.2f B/s', $bw);
            }
            $this->logger->info(sprintf('times:%d, time-last:%.2f seconds, tps=%.2f, bindwidth=%s', $this->times, $time_last, $tps, $bw));
            return NULL;
        }
        
        $this->count_times += 1;
        $msg = join('', array('#', $this->count_times, ' Hello,World.', $this->pad_bytes));
        $this->count_bytes += strlen($msg);
        
        $action = new SendRecvAction($this);
        $action->data = $msg;
        $action->remote_service = SERVICE;
        $action->remote_address = $this->peer_address;
        $action->addCallBack(array($this, 'done'));
        $action->addErrorBack(array($this, 'fail'));
        $this->action = $action;
        
        if ($this->logger->debugable()) {
            if (strlen($action->data) < 256) {
                $this->logger->debug(sprintf('  GO: (size=%d)%s', strlen($action->data), $action->data));
            }
            else {
                $this->logger->debug(sprintf('  GO: (size=%d)', strlen($action->data)));
            }
        }
        
        return $action;
    }
    
    public function done($data='')
    {
        if (!empty($data)) {
            $this->count_bytes += strlen($data);
        }
        if ($this->logger->debugable()) {
            if (strlen($data) < 256) {
                $this->logger->debug(sprintf('done CALLBACK: (size=%d)%s', strlen($data), $data));
            }
            else {
                $this->logger->debug(sprintf('done CALLBACK: (size=%d)', strlen($data)));
            }
        }
    }
    
    public function fail($reason='')
    {
        $this->logger->debug(sprintf('fail CALLBACK: "%s"', $reason));
    }
    
}   // class ClientJob

///////////////////////////////////////////////////////////////////////

$opt_parser = new OptionParser();
$opt_parser->addOption('-v', '--verbose', 'verbose', 'show verbose information', 'bool');
$opt_parser->addOption('', '--times', 'times', 'times to ping-pong');
$opt_parser->addOption('', '--bytes', 'bytes', 'size of message to ping-pong');
try {
    list($options, $args) = $opt_parser->parse( $argv );
}
catch(Exception $ex) {
    echo 'Exception: ',$ex->getMessage(),"\n";
    exit(2);
}

$verbose = false;
if (isset($options['verbose'])) {
    $verbose = $options['verbose'];
}
if (isset($options['times'])) {
    $times = $options['times'];
}
else {
    $times = 10;
}
if ($times < 1) { 
    $times = 10;
}
if (isset($options['bytes'])) {
    $bytes = $options['bytes'];
}
else {
    $bytes = 0;
}
if ($bytes < 1) {
    $bytes = 0;
} 

$logger = getLogger();
if (isset($options['verbose']) && $options['verbose']) {
    $logger->setLogLevel(TinyLogger::LEVEL_DEBUG);
}

$jube = new Jujube();
$jube->connectTCP(HOST, PORT);

$address = makeTCPAddress(HOST, PORT);
$job = new ClientJob($address, $times, $bytes);
$jube->addJob($job);

$jube->run();
